package main;

import java.io.IOException;
import java.net.*;

//Nikolas Wolfe
//4/3/09
//CNT 4007
//Reliable Data Transfer
  
public class RDTReceiver
{
	// constants
	private static final String CLOSE = "close";
	private static final String ACK_0 = "ACK(0)";
	private static final String ACK_1 = "ACK(1)";
	private static final String FALSE = "false";
	
	// receiver settings
	private final int port;
	private final DatagramSocket receiverSocket;
	private final Thread listener;
	
	// constructor
	public RDTReceiver(int portNumber) throws SocketException
	{
		this.port = portNumber;
		this.receiverSocket = new DatagramSocket(port);
		this.listener = new Thread(new ServerThread());
	}
	
	// control methods
	public void start()
	{
		listener.start();
	}
	
	public void stop()
	{
		listener.interrupt();
	}
	
	// server operation class
	private class ServerThread extends NetworkThread
	{
		private InetAddress networkIPAddress;
		private int networkPort;
		private int expectedACK;
		
		public void run()
		{
			while( !Thread.interrupted() )
			{
				try
				{
					// wait for data from sender, relay back
					DatagramPacket pkt = makeReceivePacket();
					receiverSocket.receive(pkt);
					
					// set the sender values for the receiver thread
					this.networkIPAddress = pkt.getAddress();
					this.networkPort = pkt.getPort();
					
					// processing...
					String response = convertPacketToString(pkt);
					determineACK(response);
					receiverSocket.send(makeSendPacket());
				}
				catch (IOException e)
				{
					System.out.println("IO Exception! Data not properly received!");
					Thread.currentThread().interrupt();
				}
			}
		}
		private void determineACK(String response)
		{
			int sequenceNum = getSequenceNumber(response);
			System.out.println("Sequence Number: " + sequenceNum 
					+ ", Expected: " + expectedACK);
			if( sequenceNum == expectedACK )
			{
				if (sequenceNum == 0 && !isCorrupt(response))
				{
					expectedACK = 1;
					setSendData(ACK_0);
				} 
				else if (sequenceNum == 1 && !isCorrupt(response))
				{
					expectedACK = 0;
					setSendData(ACK_1);
				}
			}
		}
		private int getSequenceNumber(String s)
		{
			int x = s.indexOf("(");
			int y = s.indexOf(")");
			String q = s.substring(x+1, y);
			String[] arr = q.split(",");
			return Integer.parseInt(arr[0].trim());
		}
		private boolean isCorrupt(String s)
		{
			int x = s.indexOf("(");
			int y = s.indexOf(")");
			String q = s.substring(x+1, y);
			String[] arr = q.split(",");
			return !arr[2].trim().equalsIgnoreCase(FALSE);
		}
		@Override
		protected InetAddress getOutgoingIPAddress()
		{
			if( networkIPAddress == null )
				throw new IllegalStateException("Sender has not initiated communication!");
			return networkIPAddress;
		}
		@Override
		protected int getOutgoingPort()
		{
			if( networkIPAddress == null )
				throw new IllegalStateException("Sender has not initiated communication!");
			return networkPort;
		}
	}
}
